﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

using WindowsFormsElementApp.Animation;
using WindowsFormsElementApp.ControlExtension.Commom;
using WindowsFormsElementApp.ControlExtension.Design;
using WindowsFormsElementApp.ControlExtension.Theme;

namespace WindowsFormsElementApp.Controls
{
    public class CMButtonPlusBasic : Button, IAnimationStaticTimer
    {
        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源，为 true；否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && components != null)
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// 设计器支持所需的方法 - 不要修改
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            components = new Container();
        }

        private enum Model
        {
            Hover,
            Press,
            Enable,
            Disable
        }

        #region 字段
        /// <summary>
        /// 动画计时器方式
        /// </summary>
        private AnimationIntervalTypes animationIntervalTypes = AnimationIntervalTypes.Add;
        /// <summary>
        /// 动画已使用的时间
        /// </summary>
        private double usedTime = 0;

        private bool original_isload = false;
        private double original_w = 0.0;// 动画对象开始制定属性原始值
        private double original_h = 0.0;// 动画对象开始制定属性原始值
        private int original_x = 0;// 动画对象开始制定属性原始值
        private int original_y = 0;// 动画对象开始制定属性原始值

        protected static Theme _theme = Theme.Defult;
        #endregion

        #region 属性

        [Description("边框宽度")]
        public float BorderWidth { get; set; } = 1;


        [Description("鼠标悬浮时背景颜色")]
        public Color HoverBackColor { get; set; } = ThemeColorFactory.GetThemeColor(_theme).ColorPrimary.Brighten();

        [Description("鼠标悬浮时字体颜色")]
        public Color HoverForeColor { get; set; } = ThemeColorFactory.GetThemeColor(_theme).ColorBackgroundBase;

        [Description("鼠标悬浮时边框颜色")]
        public Color HoverBorderColor { get; set; } = ThemeColorFactory.GetThemeColor(_theme).ColorPrimary.Brighten();


        [Description("鼠标按下时背景颜色")]
        public Color PressBackColor { get; set; } = ThemeColorFactory.GetThemeColor(_theme).ColorPrimary;

        [Description("鼠标按下时字体颜色")]
        public Color PressForeColor { get; set; } = ThemeColorFactory.GetThemeColor(_theme).ColorBackgroundBase;

        [Description("鼠标按下时边框颜色")]
        public Color PressBorderColor { get; set; } = ThemeColorFactory.GetThemeColor(_theme).ColorPrimary;


        [Description("控件启用时背景颜色")]
        public Color EnableBackColor { get; set; } = ThemeColorFactory.GetThemeColor(_theme).ColorPrimary;

        [Description("控件启用时字体颜色")]
        public Color EnableForeColor { get; set; } = ThemeColorFactory.GetThemeColor(_theme).ColorBackgroundBase;

        [Description("控件启用时边框颜色")]
        public Color EnableBorderColor { get; set; } = ThemeColorFactory.GetThemeColor(_theme).ColorPrimary;


        [Description("圆角半径")]
        public int Radius { get; set; } = 6;

        private Model paintmodel = Model.Enable;

        private AnimationClass animation = new AnimationClass();
        /// <summary>
        /// 动画设置
        /// </summary>
        [Description("动画设置")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public AnimationClass Animation
        {
            get
            {
                return animation;
            }
            set
            {
                animation = value;
            }
        }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        protected new bool DesignMode
        {
            get
            {
                if (GetService(typeof(IDesignerHost)) != null || LicenseManager.UsageMode == LicenseUsageMode.Designtime)
                {
                    return true;   //界面设计模式
                }
                else
                {
                    return false;//运行时模式
                }
            }
        }
        #endregion


        public CMButtonPlusBasic()
        {
            InitializeComponent();

            //这些得带上，不然会有黑边
            FlatStyle = FlatStyle.Flat;
            FlatAppearance.BorderSize = 0;
            FlatAppearance.BorderColor = Color.FromArgb(0, 0, 0, 0);
            FlatAppearance.MouseDownBackColor = Color.Transparent;
            FlatAppearance.MouseOverBackColor = Color.Transparent;

            SetStyle(ControlStyles.UserPaint, true);

            Height = 35;
            Width = 85;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            //这个不能去，而且得放在前面，不然会有黑框之类的莫名其妙的东西
            base.OnPaint(e);

            Color colorback, colorfore, colorBorder;
            switch (paintmodel)
            {
                case Model.Hover:
                    colorback = HoverBackColor;
                    colorfore = HoverForeColor;
                    colorBorder = HoverBorderColor;
                    break;
                case Model.Press:
                    colorback = PressBackColor;
                    colorfore = PressForeColor;
                    colorBorder = PressBorderColor;
                    break;
                case Model.Enable:
                    colorback = EnableBackColor;
                    colorfore = EnableForeColor;
                    colorBorder = EnableBorderColor;
                    break;
                default:
                    colorback = Color.Transparent;
                    colorfore = Color.Transparent;
                    colorBorder = ThemeColorFactory.GetThemeColor(_theme).ColorFontPlaceholder;
                    break;
            }

            Draw(e.ClipRectangle, e.Graphics, colorback, colorBorder);
            DrawText(e.ClipRectangle, e.Graphics, colorfore);
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            paintmodel = Model.Hover;
            base.OnMouseEnter(e);

            if (DesignMode)
                return;

            LoadOriginal(original_isload);
            animationIntervalTypes = AnimationIntervalTypes.Add;
            AnimationStaticTimer.AnimationStart(this);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            paintmodel = Model.Enable;
            base.OnMouseLeave(e);

            if (DesignMode)
                return;

            LoadOriginal(original_isload);
            animationIntervalTypes = AnimationIntervalTypes.Subtrac;
            AnimationStaticTimer.AnimationStart(this);
        }

        protected override void OnMouseDown(MouseEventArgs mevent)
        {
            paintmodel = Model.Press;
            base.OnMouseDown(mevent);
        }

        protected override void OnMouseUp(MouseEventArgs mevent)
        {
            paintmodel = Model.Hover;
            base.OnMouseUp(mevent);
        }

        protected override void OnEnabledChanged(EventArgs e)
        {
            paintmodel = Enabled ? Model.Enable : Model.Disable;
            Invalidate();//false 转换为true的时候不会刷新 这里强制刷新下
            base.OnEnabledChanged(e);
        }

        private void Draw(Rectangle rectangle, Graphics g, Color beginCcolor, Color borderColor)
        {
            int span = 2;
            //抗锯齿
            g.SmoothingMode = SmoothingMode.AntiAlias;

            //填充
            var gPath = ControlCommom.TransformCircular(new RectangleF(rectangle.X, rectangle.Y, rectangle.Width - span, rectangle.Height - span), Radius);
            g.FillPath(new SolidBrush(beginCcolor), gPath);

            //描边
            g.DrawPath(new Pen(borderColor, BorderWidth), gPath);
        }

        private void DrawText(Rectangle rectangle, Graphics g, Color color)
        {
            SolidBrush sbr = new SolidBrush(color);
            RectangleF rect;
            switch (TextAlign)
            {
                case ContentAlignment.MiddleCenter:
                    rect = getTextRec(rectangle, g);
                    break;
                default:
                    rect = getTextRec(rectangle, g);
                    break;
            }
            g.DrawString(Text, Font, sbr, rect);
        }

        private RectangleF getTextRec(Rectangle rectangle, Graphics g)
        {
            var rect = new RectangleF();
            var size = g.MeasureString(Text, Font);
            if (size.Width > rectangle.Width || size.Height > rectangle.Height)
            {
                rect = rectangle;
            }
            else
            {
                rect.Size = size;
                rect.Location = new PointF(rectangle.X + (rectangle.Width - size.Width) / 2, rectangle.Y + (rectangle.Height - size.Height) / 2);
            }
            return rect;
        }

        #region 私有方法

        /// <summary>
        /// 初始化控件原始位置信息
        /// </summary>
        /// <param name="_isload"></param>
        private void LoadOriginal(bool _isload)
        {
            if (!_isload)
            {
                original_w = Width;
                original_h = Height;
                original_x = Location.X;
                original_y = Location.Y;
                original_isload = true;
            }
        }

        #endregion

        #region 公开方法

        /// <summary>
        /// 缩放动画中(禁止手动调用)
        /// </summary>
        [Description("缩放动画中(禁止手动调用)")]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void Animationing()
        {
            bool finish = false;
            if (animationIntervalTypes == AnimationIntervalTypes.Add)
            {
                usedTime += AnimationStaticTimer.timer.Interval;
                if (usedTime > Animation.ZoomTime)
                {
                    usedTime = Animation.ZoomTime;
                    AnimationStaticTimer.AnimationStop(this);
                    finish = true;
                }
            }
            else
            {
                usedTime -= AnimationStaticTimer.timer.Interval;
                if (usedTime < 0)
                {
                    usedTime = 0;
                    AnimationStaticTimer.AnimationStop(this);
                    finish = true;
                }
            }

            double progress = AnimationTimer.GetProgress(animationIntervalTypes == AnimationIntervalTypes.Add ? Animation.ZoomMagnifyTypes : Animation.ZoomShrinkTypes, Animation.Options, usedTime);
            if (finish)
            {
                if (progress < 0)
                    progress = 0;
                if (progress > 1)
                    progress = 1;
            }

            var control = this;
            control.Width = (int)(control.original_w + Animation.ZoomValue * progress);
            control.Height = (int)(control.original_h + Animation.ZoomValue * progress);
            int x = (int)((original_w - control.Width) / 2.0);
            int y = (int)((original_h - control.Height) / 2.0);
            control.Location = new Point(original_x + x, original_y + y);
        }

        #endregion

        #region 类

        /// <summary>
        /// 动画设置
        /// </summary>
        [Description("动画设置")]
        [TypeConverter(typeof(EmptyConverter))]
        public class AnimationClass
        {
            private int zoomValue = 3;
            /// <summary>
            /// 缩放值
            /// </summary>
            [Description("缩放值")]
            [DefaultValue(3)]
            public int ZoomValue
            {
                get
                {
                    return zoomValue;
                }
                set
                {
                    zoomValue = value;
                }
            }

            /// <summary>
            /// 动画要变换的总时间(默认值50.0)
            /// </summary>
            [Description("动画要变换的总时间(默认值50.0)")]
            [DefaultValue(50.0)]
            public double ZoomTime
            {
                get { return Options.AllTransformTime; }
                set
                {
                    if (value > AnimationStaticTimer.leisure_maxtime / 2)
                        value = AnimationStaticTimer.leisure_maxtime / 2;

                    Options.AllTransformTime = value;
                }
            }

            private AnimationTypes zoomMagnifyTypes = AnimationTypes.EaseOut;
            /// <summary>
            /// 放大动画类型
            /// </summary>
            [Description("放大动画类型")]
            [DefaultValue(AnimationTypes.EaseOut)]
            public AnimationTypes ZoomMagnifyTypes
            {
                get
                {
                    return zoomMagnifyTypes;
                }
                set
                {
                    zoomMagnifyTypes = value;
                }
            }

            private AnimationTypes zoomShrinkTypes = AnimationTypes.EaseIn;
            /// <summary>
            /// 缩小动画类型
            /// </summary>
            [Description("缩小动画类型")]
            [DefaultValue(AnimationTypes.EaseIn)]
            public AnimationTypes ZoomShrinkTypes
            {
                get
                {
                    return zoomShrinkTypes;
                }
                set
                {
                    zoomShrinkTypes = value;
                }
            }

            /// <summary>
            /// 动画曲线幂(默认值3.0)
            /// (限于EaseIn、EaseOut、EaseBoth、BackIn、BackOut、BackBoth)
            /// </summary>
            [Description("动画曲线幂(默认值3)")]
            [DefaultValue(3.0)]
            public double Power
            {
                get { return Options.Power; }
                set { Options.Power = value; }
            }

            /// <summary>
            /// 收缩与相关联的幅度动画。此值必须大于或等于 0。 默认值为 0.3。
            /// (限于BackIn、BackOut、BackBoth)
            /// </summary>
            [Description("收缩与相关联的幅度动画。此值必须大于或等于 0。 默认值为 0.3")]
            [DefaultValue(0.3)]
            public double Amplitude
            {
                get { return Options.Amplitude; }
                set { Options.Amplitude = value; }
            }

            /// <summary>
            /// 反弹次数。值必须大于或等于零(默认值为3)
            /// (限于BounceIn、BounceOut、BounceBoth）
            /// </summary>
            [Description("反弹次数。值必须大于或等于零(默认值为3)")]
            [DefaultValue(3)]
            public int Bounces
            {
                get { return Options.Bounces; }
                set { Options.Bounces = value; }
            }

            /// <summary>
            /// 指定反弹动画的弹性大小。虽然较高的值都会导致反弹 （弹性较小），此属性中的结果很少或者反弹低值会丢失反弹 （弹性较大） 之间的高度。此值必须是正数(默认值为 2.0)
            /// (限于BounceIn、BounceOut、BounceBoth）
            /// </summary>
            [Description("指定反弹动画的弹性大小。虽然较高的值都会导致反弹 （弹性较小），此属性中的结果很少或者反弹低值会丢失反弹 （弹性较大） 之间的高度。此值必须是正数(默认值为 2.0)")]
            [DefaultValue(2.0)]
            public double Bounciness
            {
                get { return Options.Bounciness; }
                set { Options.Bounciness = value; }
            }

            /// <summary>
            /// 目标来回滑过动画目标的次数。此值必须大于或等于0 (默认值为3)
            /// (限于ElasticIn、ElasticOut、ElasticBoth）
            /// </summary>
            [Description("目标来回滑过动画目标的次数。此值必须大于或等于0 (默认值为3)")]
            [DefaultValue(3)]
            public int Oscillations
            {
                get { return Options.Oscillations; }
                set { Options.Oscillations = value; }
            }

            /// <summary>
            /// 弹簧铡度。 越小的 Springiness 值为，严格 spring，通过每个振动的强度减小的速度越快弹性。一个正数(默认值为3.0)
            /// (限于ElasticIn、ElasticOut、ElasticBoth）
            /// </summary>
            [Description("弹簧铡度。 越小的 Springiness 值为，严格 spring，通过每个振动的强度减小的速度越快弹性。一个正数(默认值为3.0)")]
            [DefaultValue(3.0)]
            public double Springiness
            {
                get { return Options.Springiness; }
                set { Options.Springiness = value; }
            }

            private AnimationOptions options = new AnimationOptions()
            {
                AllTransformTime = 50,
                Amplitude = 0.3
            };
            [Browsable(false)]
            [EditorBrowsable(EditorBrowsableState.Never)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
            public AnimationOptions Options
            {
                get { return options; }
                set { options = value; }
            }
        }

        #endregion
    }
}
